/** Function.prototype.call*/
/** 原理：this是.前那个对象*/
/*
function getName(){
  console.log(this.name);
}

let obj = {name: 'ahhh'};

obj.getName = getName;
obj.getName();
delete obj.getName;
*/

/** 实现call*/
!(function (prototype) {
  function call2(context) {
    context.fn = this; //context.fn = getName
    context.fn(); //getName() ---> 此时 getName执行时 内部的this就指向 context, 即getName.call(obj) 传来的obj
    delete context.fn;
  }

  prototype.call2 = call2;
})(Function.prototype);

function getName(){
  console.log(this.name);
}

let obj = {name: 'ahhh'};

getName.call(obj); // ahhh




/** 完整版call*/
!(function (prototype) {
  function getDefaultContext(context){
    // null undefined -> context = window
    context = context || window;

    // 如果是基本值的话 包装成对象类型
    /*
      let a = 1;
      typeof a -> number
      a = new a.constructor(1)
      typeof a -> object
    */
    const type = typeof context;
    if (['number', 'string', 'boolean'].includes(type)) {
      context = new context.constructor();
    }
    return context
  }
  function call3(context, ...args) {
    context = getDefaultContext(context)
    // 为了防止fn和本来人家有的重名↓ 使用Symbol
    const symbol = Symbol('fn');
    context[symbol] = this;
    context[symbol](...args);
    delete context[symbol];
  }
  prototype.call3 = call3;


  /** apply*/
  function apply(context, args) {
    context = getDefaultContext(context);
    // 为了防止fn和本来人家有的重名↓ 使用Symbol
    const symbol = Symbol('fn');
    context[symbol] = this;
    context[symbol](...args);
    delete context[symbol];
  }

  prototype.apply = apply;
})(Function.prototype);

function getName2(arg1,arg2){
  console.log(this.name,arg1,arg2);
}

let obj2 = {name: 'ahhh'};

getName2.call(obj2,1,2); // ahhh 1 2
getName2.apply(obj2,[1,2]); //ahhh 1 2
/** call性能远高于apply(v8源码里是apply是调用的call)
 * 可在这里进行测试 近乎一倍的速度 https://jsperf.com/ */



